package world;

import block.Blocks;
import util.HexYZXArray;
import util.YZXUtil;

public class ChunkSlice {
	public final static int ARRAY_SIZE = 4096;
	public final static int X_SIZE = 16;
	public final static int Y_SIZE = 16;
	public final static int Z_SIZE = 16;
	private int yBasePos;
	private int blockCount;

	private byte[] blockLSBArray;
	private byte[] blockMSBArray;

	private HexYZXArray localLightArray;
	private HexYZXArray globalLightArray;
	
	public ChunkSlice( int yBase, boolean globalLightEnabledYN) {
		this.yBasePos = yBase;
		this.blockLSBArray = new byte[ARRAY_SIZE];
		this.blockMSBArray = new byte[ARRAY_SIZE];
		this.localLightArray = new HexYZXArray(ARRAY_SIZE);

		if (globalLightEnabledYN) {
			this.globalLightArray = new HexYZXArray(ARRAY_SIZE);
		}
	}

	public int getBlockID(int x, int y, int z) {
		return getBlockID(YZXUtil.toIndex(x, y, z));
	}

	public void setBlockID(int x, int y, int z, int newBlockID) {
		int index = YZXUtil.toIndex(x, y, z);
		int oldBlockID = getBlockID(index);
		this.countBlock(oldBlockID, newBlockID);
		this.setBlockID(index, newBlockID);
	}

	public boolean isEmpty() {
		return this.blockCount == 0;
	}

	public int getLocalLightArray(int x, int y, int z) {
		return this.localLightArray.get(x, y, z);
	}

	public void setLocalLightArray(int x, int y, int z, int value) {
		this.localLightArray.set(x, y, z, value);
	}

	public int getGlobalLightArray(int x, int y, int z) {
		return this.globalLightArray.get(x, y, z);
	}

	public void setGlobalLightArray(int x, int y, int z, int value) {
		this.globalLightArray.set(x, y, z, value);
	}

	public void removeInvalidBlocks() {
		this.blockCount = 0;

		for (int i = 0; i < X_SIZE; ++i) {
			for (int j = 0; j < Y_SIZE; ++j) {
				for (int k = 0; k < Z_SIZE; ++k) {
					int index = YZXUtil.toIndex(i, j, k);
					int blockID = getBlockID(index);

					if (blockID == 0) {
						continue;
					}

					if (Blocks.values[blockID] == null) {
						this.blockLSBArray[index] = 0;
						this.blockMSBArray[index] = 0;
					} else {
						++this.blockCount;
					}

				}
			}
		}
	}

	// -----------------------------------------------------------------private methods
	private int getBlockID(int index) {
		int lsb = this.blockLSBArray[index] & 255;
		int hsb = this.blockMSBArray[index] & 255;
		return hsb << 8 | lsb;
	}

	private void setBlockID(int index, int newBlockID) {
		this.blockLSBArray[index] = (byte) (newBlockID & 255);
		this.blockMSBArray[index] = (byte) ((newBlockID & 3840) >> 4);
	}

	private void countBlock(int oldBlockID, int newBlockID) {
		if (oldBlockID == 0 && newBlockID != 0) {
			++this.blockCount;
		} else if (oldBlockID != 0 && oldBlockID == 0) {
			--this.blockCount;
		}
	}

	// -----------------------------------------------------------------getter setter
	public int getYBasePos() {
		return this.yBasePos;
	}

	public byte[] getBlockLSBArray() {
		return blockLSBArray;
	}

	public void setBlockLSBArray(byte[] blockLSBArray) {
		this.blockLSBArray = blockLSBArray;
	}

	public byte[] getBlockMSBArray() {
		return blockMSBArray;
	}

	public void setBlockMSBArray(byte[] blockMSBArray) {
		this.blockMSBArray = blockMSBArray;
	}

	public HexYZXArray getLocalLightArray() {
		return localLightArray;
	}

	public void setLocalLightArray(HexYZXArray localLightArray) {
		this.localLightArray = localLightArray;
	}

	public HexYZXArray getGlobalLightArray() {
		return globalLightArray;
	}

	public void setGlobalLightArray(HexYZXArray globalLightArray) {
		this.globalLightArray = globalLightArray;
	}
}
